using System;
using System.Collections.Generic;
using Game.Scripts.Constant;
using Game.Scripts.Entity;
using Game.Scripts.Interface;
using Game.Scripts.Utility;
using Sirenix.OdinInspector;
using Sirenix.Serialization;
using UniRx;
using UnityEngine;
using Zenject;
using Random = UnityEngine.Random;

namespace Game.Scripts.Service
{
    public class RoadTileService : SerializedMonoBehaviour
    {
        [OdinSerialize] private List<IRoadTile> roadTiles;
        private const int _middleIndex = 1;
        private const int _roadTileLength = 210;
        private List<IRoadTile> originalRoadTilesList;
        private GameService _gameService;
        private IkunBus _ikunBus;
        [ReadOnly] public int tilePassedCount;
        [ReadOnly] public int tilePassedTarget;
        
        
        [Inject]
        public void Construct(GameService gameService, IkunBus ikunBus)
        {
            _gameService = gameService;
            _ikunBus = ikunBus;
        }


        private void Awake()
        {
            originalRoadTilesList = new List<IRoadTile>(roadTiles);
        }


        private void Start()
        {
            _gameService.currentGameLevel.Subscribe(next =>
            {
                // Debug.Log($"next is: {next}");
                LoadGameLevelConfig(next);
            });
        }


        private void LoadGameLevelConfig(int gameLevel)
        {

            Debug.Log($"load game level {gameLevel}");
            // reset the passed tile count
            tilePassedCount = 0;
            
            // check if use fallout first  
            int fixedConfigSize = _gameService.gameLevelConfig.gameLevels.Count;
            if (gameLevel >= fixedConfigSize)
            {
                if (gameLevel < roadTiles.Count)
                {
                    Debug.LogError("break the assumption the first three game level should be hard code configured", this);
                    return;
                }
                Vector2 tileRange = _gameService.gameLevelConfig.tileCountFallback;
                int targetTileNum = Random.Range((int)tileRange[0],(int)tileRange[1]);
                tilePassedTarget = targetTileNum;
                HandleBombTimerConfig(targetTileNum * _gameService.gameLevelConfig.timeLimitPerTile);
            }
            else
            {
                // means we can mark the end point right now, are not using the tilePassedTarget field
                tilePassedTarget = -1;
                GameLevel gameLevelConfig = _gameService.gameLevelConfig.gameLevels[gameLevel];
                HandleBombTimerConfig(gameLevelConfig.timeLimit);
                if (gameLevel < roadTiles.Count)
                {
                    roadTiles[gameLevel].MarkEndPoint();
                }
            }
        }


        public void ClearMarkedEndPoint()
        {
            foreach (IRoadTile roadTile in roadTiles)
            {
                roadTile.UnMarkEndPoint();
            }
        }



        public void PlaceEndPointIfConfigured()
        {
            if (tilePassedTarget == -1)
            {
                return;
            }

            if (tilePassedCount + 2 == tilePassedTarget)
            {
                roadTiles[^1].MarkEndPoint();
            }
        }



        private void HandleBombTimerConfig(float timeLimit)
        {
            _ikunBus.HandleBombTimerConfig(timeLimit);
        }


        public void HandleExtendRoad(IRoadTile roadTile)
        {
            int index = roadTiles.FindIndex(r => r == roadTile);
            if (index == _middleIndex)
            {
                MoveRoadTileEndToFront();
            }
        }


        private void MoveRoadTileEndToFront()
        {
            roadTiles[0].MoveToFront(roadTiles.Count * _roadTileLength);
            roadTiles = roadTiles.ShiftLeft(1);
        }

        public void ResetTilesState()
        {
            roadTiles = new List<IRoadTile>(originalRoadTilesList);
            foreach (IRoadTile roadTile in roadTiles)
            {
                roadTile.ResetPosition();
                roadTile.ClearPlaceableRoadItem();
                roadTile.SpawnPlaceableRoadItem();
            }
        }
    }
}